﻿namespace Guia.Elements
{
    using System.Windows.Automation;
    using Guia.Core;
    using Guia.Elements.PatternServants;
    using Guia.Locator;

    /// <summary>
    /// This class represents a MenuItem within a menu. 
    /// </summary>
    public class MenuItem : AbstractMenuItem, IInvoke, IExpandCollapse
    {
        // TODO: Not that beautiful: A lot of code duplication in this class and other control-wrapper (e.g. CheckBox).

        /// <summary>
        /// Represents a helper-servant for the Invoke-pattern.
        /// </summary>
        protected readonly IInvoke InvokeServant;

        /// <summary>
        /// Represents a helper-servant for the ExpandCollapse-pattern.
        /// </summary>
        private readonly IExpandCollapse expandCollapseServant;

        /// <summary>
        /// Represents a helper-servant for the Toggle-pattern.
        /// </summary>
        private readonly IToggle toggleServant;
        
        /// <summary>
        /// Initializes a new instance of the MenuItem class. 
        /// </summary>
        /// <param name="automationElement">The AutomationElement representating the MenuItem.</param>
        public MenuItem(AutomationElement automationElement)
            : base(automationElement)
        {
            this.InvokeServant = new InvokeImpl(this);
            this.toggleServant = new ToggleImpl(this);
            this.expandCollapseServant = new ExpandCollapseImpl(this);
        }

        /// <summary>
        /// Gets the default-condition to find a control by its type.
        /// </summary>
        public static SearchCondition ControlTypeCondition
        {
            get { return SearchCondition.ByControlType(ControlType.MenuItem); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the state of this MenuItem is expanded or not.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the IsExpanded-action is not supported on the particular MenuItem.</exception>
        public bool IsExpanded
        {
            get
            {
                return this.expandCollapseServant.IsExpanded;
            }

            set
            {
                this.expandCollapseServant.IsExpanded = value;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this MenuItem is checked or not.
        /// If this MenuItem is not selectable, an exception is thrown.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the IsChecked-action is not supported on the particular MenuItem.</exception>
        public bool IsChecked
        {
            get { return this.toggleServant.IsOn; }
        }

        /// <summary>
        /// Invokes this MenuItem.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the invoke-action is not supported on the particular MenuItem.</exception>
        public void Invoke()
        {
            this.InvokeServant.Invoke();
        }

        /// <summary>
        /// Toggle the checkbox's value.
        /// If this MenuItem is not selectable, an exception is thrown.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the toggle-action is not supported on the particular MenuItem.</exception>
        public void Toggle()
        {
            this.toggleServant.Toggle();
        }

        /// <summary>
        /// Check the MenuItem.
        /// If this MenuItem is not selectable, an exception is thrown.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the Check-Action is not supported on the particular MenuItem.</exception>
        public void Check()
        {
            if (!this.toggleServant.IsOn)
            {
                this.toggleServant.Toggle();
            }
        }

        /// <summary>
        /// Uncheck the MenuItem.
        /// If this MenuItem is not selectable, an exception is thrown.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the Uncheck-Action is not supported on the particular MenuItem.</exception>
        public void UnCheck()
        {
            if (!this.toggleServant.IsOff)
            {
                this.toggleServant.Toggle();
            }
        }

        /// <summary>
        /// Expands the MenuItem.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the Expand-Action is not supported on the particular MenuItem.</exception>
        public void Expand()
        {
            this.expandCollapseServant.Expand();
        }

        /// <summary>
        /// Collapses the MenuItem.
        /// </summary>
        /// <exception cref="OperationNotSupportedException">This exception is thrown when the Collapse-Action is not supported on the particular MenuItem.</exception>
        public void Collapse()
        {
            this.expandCollapseServant.Collapse();
        }

        /// <summary>
        /// Get all MenuItem instances belonging to this MenuItem (Submenu).
        /// </summary>
        /// <returns>An array of MenuItems.</returns>
        public override MenuItem[] GetAllMenuItems()
        {
            try
            {
                this.Expand();
            }
            catch (OperationNotSupportedException)
            {
                // there may be no sub-items.
            }

            return base.GetAllMenuItems();
        }

        /// <summary>
        /// Get the MenuItem with the given automationId.
        /// </summary>
        /// <param name="automationId">The automationId of the MenuItem.</param>
        /// <returns>A MenuItem.</returns>
        protected override MenuItem GetMenuItem(string automationId)
        {
            try 
            {
                this.Expand();
            }
            catch (OperationNotSupportedException)
            {
                // there may be no sub-items.
            }

            return base.GetMenuItem(automationId);
        }
    }
}